package org.example;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 负载均衡算法 --- 平滑加权轮训算法
 * A: 5
 * B: 1
 * C: 1
 * 平滑加权: AABACAA (而不是AAAAABC)
 * 应用: nginx
 *
 * 三个属性:
 * ip: 地址
 * weight: 静态, 5,1,1
 * currentWeight: 动态
 *
 * 例子:
 * currentWeight: 0, 0, 0
 *
 * currentWeight += weight      max[currentWeight]      max[currentWeight] -= sum(weight)7      return
 * 5,1,1                        5                       -2,1,1                                  A
 * 3,2,2                        3                       -4,2,2                                  A
 * 1,3,3                        3                       1,-4,3                                  B
 * 6,-3,4                       6                       -1,-3,4                                 A
 * 4,-2,5                       5                       4,-2,-2                                 C
 * 9,-1,-1                      9                       2,-1,-1                                 A
 * 7,0,0                        7                       0,0,0                                   A
 * ....
 * @author shenguangyang
 */
public class LbRoundRobinSmoothWeight extends LoadBalance {
    private static final Map<String, Weight> weightMap = new LinkedHashMap<>();
    public static void main(String[] args) {
        LoadBalance loadBalance = new LbRoundRobinSmoothWeight();
        loadBalance.printf();
    }

    /**
     *
     * @return 返回ip
     */
    @Override
    public String getServer() {
        int totalWeight = 0;
        for (Integer weight : ServerIps.WEIGHT_LIST.values()) {
            totalWeight += weight;
        }

        if (weightMap.isEmpty()) {
            for (String ip : ServerIps.WEIGHT_LIST.keySet()) {
                Integer weight = ServerIps.WEIGHT_LIST.get(ip);
                weightMap.put(ip, new Weight(ip, weight, 0));
            }
        }

        // currentWeight += weight
        for (Weight weight : weightMap.values()) {
            weight.setCurrentWeight(weight.getCurrentWeight() + weight.getWeight());
        }

        // max[currentWeight]
        Weight maxCurrentWeight = null;
        for (Weight weight : weightMap.values()) {
            if (maxCurrentWeight == null || maxCurrentWeight.getCurrentWeight() <= weight.getCurrentWeight()) {
                maxCurrentWeight = weight;
            }
        }

        // max[currentWeight] -= sum(weight)7
        if (maxCurrentWeight == null) {
            throw new RuntimeException("get server fail, maxCurrentWeight is null");
        }
        maxCurrentWeight.setCurrentWeight(maxCurrentWeight.getCurrentWeight() - totalWeight);
        return maxCurrentWeight.getIp();
    }
}
